cmake_minimum_required(VERSION 3.10)
project(tinyndarray)

set(CMAKE_CXX_STANDARD 17)

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    set(LINK_TYPE STATIC)
else()
    set(LINK_TYPE SHARED)
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()

# Print make commands for debug
# set(CMAKE_VERBOSE_MAKEFILE 1)

# Set default build type
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
set(PROJECT_VERSION 1.0.0)
# Output `compile_commands.json`
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Set output directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# ====================== 选项配置 ======================
option(TINYNDARRAY_USE_SANITIZERS "Enable address and undefined behavior sanitizers" ON)
option(TINYNDARRAY_USE_OPENMP "Enable OpenMP parallelization" ON)
option(TINYNDARRAY_BUILD_PYTHON "Enable Python Interface" ON)

# Warning options
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    set(warning_options "-Wall -Wextra -Wconversion")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    set(warning_options "-Wall -Wextra -Wconversion")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    set(warning_options "/W4")
else()
    message(WARNING "Unsupported compiler for warning options")
    message("CMAKE_CXX_COMPILER_ID is ${CMAKE_CXX_COMPILER_ID}")
endif()

# ------------------------------------------------------------------------------
# ----------------------------- Internal Libraries -----------------------------
# ------------------------------------------------------------------------------

find_package(Threads)

add_subdirectory(third_party/cnpy)
include_directories(third_party/half/include)
# 主库
add_library(tinyndarray STATIC
    src/core.cpp
    src/arithmetic.cpp
    src/shape_manipulation.cpp
    src/reduction.cpp
    src/random.cpp
    src/utils.cpp
    src/io.cpp
    src/tensor_ops.cpp
    src/unary.cpp
    src/binary.cpp
    src/broadcast.cpp
    src/element_proxy.cpp
    src/view.cpp
    src/misc.cpp
    src/quant.cpp
)

target_include_directories(tinyndarray PRIVATE "include/internal")
# ====================== Sanitizers 配置 ======================
if(TINYNDARRAY_USE_SANITIZERS AND UNIX_COMPILER)
    # 仅在Debug/RelWithDebInfo构建类型下启用
    if(CMAKE_BUILD_TYPE MATCHES "Debug|RelWithDebInfo")
        set(SANITIZER_FLAGS "-fsanitize=address,undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls")

        # 链接器标志
        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS}")
        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SANITIZER_FLAGS}")

        # 编译器标志
        add_compile_options(${SANITIZER_FLAGS})

        message(STATUS "Enabled Address and Undefined Behavior Sanitizers")
    else()
        message(STATUS "Sanitizers disabled for ${CMAKE_BUILD_TYPE} build")
    endif()
endif()


# 添加头文件目录
target_include_directories(tinyndarray
    PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

# 链接 cnpy
target_link_libraries(tinyndarray PRIVATE cnpy Threads::Threads)

# 定义实现宏（仅在库内部使用）
target_compile_definitions(tinyndarray PRIVATE
    TINYNDARRAY_IMPLEMENTATION
)

# 设置安装规则
install(
    TARGETS tinyndarray cnpy
    EXPORT tinyndarrayTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

install(
    DIRECTORY include/tinyndarray
    DESTINATION include
    FILES_MATCHING PATTERN "*.h"
)

# 安装 cnpy 头文件
install(
    DIRECTORY third-party/cnpy/
    DESTINATION include/cnpy
    FILES_MATCHING
    PATTERN "*.h"
    PATTERN "*.hpp"
)

install(
    EXPORT tinyndarrayTargets
    FILE tinyndarrayTargets.cmake
    NAMESPACE tinyndarray::
    DESTINATION lib/cmake/tinyndarray
)

# 创建配置文件
include(CMakePackageConfigHelpers)
configure_package_config_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/tinyndarrayConfig.cmake
    INSTALL_DESTINATION lib/cmake/tinyndarray
)

write_basic_package_version_file(
    ${CMAKE_CURRENT_BINARY_DIR}/tinyndarrayConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY AnyNewerVersion
)

install(
    FILES
    ${CMAKE_CURRENT_BINARY_DIR}/tinyndarrayConfig.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/tinyndarrayConfigVersion.cmake
    DESTINATION lib/cmake/tinyndarray
)

if(TINYNDARRAY_BUILD_PYTHON)
    add_subdirectory(python)
endif()
# 测试
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(test)
endif()
